
import java.util.*;
import java.util.regex.*;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Dung Doan
 */
public class ParseWhere {
    
    public static int countOpenOp(String str)
    {
        int num = 0;
        for (int i = 0 ; i < str.length() ; i++)
            if (str.charAt(i) == '(')
                num = num + 1;
        return num;
    }
    public static int countCloseOp(String str)
    {
        int num = 0;
        for (int i = 0 ; i < str.length() ; i++)
            if (str.charAt(i) == ')')
                num = num + 1;
        return num;
    }
    public static String Normalize(String str)
    {
        String result = new String(str);
        int i;
        for (i = 0 ; i < result.length() ; i++)
            if (result.charAt(i) != ' ')
                break;
        
        result = result.substring(i);
        for (i = result.length() - 1 ; i >= 0 ; i--)
            if (result.charAt(i) != ' ')
                break;
        result = result.substring(0, i + 1);
        boolean flag = true;
        for (i = 0 ; i < result.length(); i++)
            if (result.charAt(i) != ' ')
            {
                flag = false;
                break;
            }
        if (flag == true)
            result = null;
        return result;
    }
    public static String EliminateOpenCloseOp(String str)
    {
        String result;
        int len = str.length();
        if (str.charAt(0) == '(' && str.charAt(len - 1) == ')')
            return str.substring(1, len - 1);
        if (str.charAt(0) == '(' && str.charAt(len - 1) != ')')
            return str.substring(1, len);
        if (str.charAt(0) != '(' && str.charAt(len - 1) == ')')
            return str.substring(0, len - 1);
        return str;
            
    }
    public static String getOperator(String query)
    {
        int openOp = 0;
        int closeOp = 0;
        for (int i = 0 ; i < query.length() ; i++)
        {
            
            if (query.charAt(i) == '(')    
                openOp = openOp + 1;
                
            
            if (query.charAt(i) == ')')
                closeOp = closeOp + 1;
            
            
            String subStr = query.substring(i);
            if (hasAND(subStr) && closeOp == openOp)
                return "AND";
            if (hasOR(subStr) && closeOp == openOp) 
                return "OR";
            
        }
        return null;
    }
    
    
    public static boolean hasAND(String str)
    {
        if (str.indexOf("AND") == 0 || str.indexOf("and") == 0 || str.indexOf("And") == 0 || str.indexOf("aNd") == 0
                || str.indexOf("anD") == 0 || str.indexOf("ANd") == 0 ||
                str.indexOf("AnD") == 0 || str.indexOf("aND") == 0)
            return true;
        return false;
    }
    
    public static boolean hasOR(String str)
    {
        if (str.indexOf("OR") == 0 || str.indexOf("or") == 0 || str.indexOf("Or") == 0
                || str.indexOf("oR") == 0)
            return true;
        return false;
    }
    public static ArrayList<String> getOperands(String query)
    {
        ArrayList<String> arrOperands = new ArrayList<String>();
        int openOp = 0;
        int closeOp = 0;
        int startIndex = 0;
        
        for (int i = 0 ; i < query.length() ; i++)
        {
            //System.out.println(query.charAt(i));
            if (query.charAt(i) == '(')    
                openOp = openOp + 1;
                
            
            if (query.charAt(i) == ')')
                closeOp = closeOp + 1;
                
            
            
            String subStr = query.substring(i);
            
            
            if ((hasAND(subStr) || hasOR(subStr) || i == query.length() - 1) && (openOp == closeOp))
            {
                
                openOp = 0;
                closeOp = 0;
                String str = Normalize(query.substring(startIndex, i));
                str = EliminateOpenCloseOp(str);
                arrOperands.add(str);
                if (hasAND(subStr))
                    startIndex = i + 3;
                else
                    startIndex = i + 2;
                //i = startIndex;
                str = Normalize(query.substring(startIndex));
                str = EliminateOpenCloseOp(str);
                arrOperands.add(str);
                break;
                
            }
         
        }
        return arrOperands;
    }
    public static boolean QueryParse(ArrayList<String> columnName, RowData data, String query)
    {
        
        String REGEX = "WHERE ";
        Pattern p = Pattern.compile(REGEX);
        String[] items = p.split(query);
        //items = RemoveFirstElement(items);
        query = items[1];
        
        if (countOpenOp(query) != countCloseOp(query))
            return false;
        
        Node root = null;
        if (getOperator(query) == null)
        {
            
            root = new ExpressionNode(query);
        }

        else
        {
            ArrayList<String> subNodes = getOperands(query);
            root = new OperationNode(getOperator(query));
            for (int i = 0 ; i < subNodes.size() ; i++)
            {
                String node = subNodes.get(i);
                if (getOperator(node) == null)
                {
                    
                    root.AddSubNode(new ExpressionNode(node));
                }
                else
                {   
                    
                    root.AddSubNode(new OperationNode(node));
                }
                
            }
        }
        //root.Display();
        //return true;   
        return root.check(columnName, data);
        
    }
    public static void main(String[] args)
    {
        
//        System.out.println(getOperator(query));
//        System.out.println(getOperator(query1));
//        System.out.println(getOperator(query2));
//        System.out.println(getOperator(query3));
//        System.out.println(getOperator(query4));
        
//        ArrayList<String> arr = getOperands(query);
//        
//            
//        for (int i = 0 ; i < arr.size() ; i++)
//            System.out.println(arr.get(i));
        
        
        
        
        
        
        
        
        
        
        
        ArrayList<CellDefinition> cell_list = new ArrayList<CellDefinition>();
        cell_list.add(new CellDefinition("Doan Anh Dung", "string"));
        cell_list.add(new CellDefinition(1234, "int"));
        cell_list.add(new CellDefinition(8, "int"));
        
        cell_list.add(new CellDefinition("A", "string"));        
        RowData data = new RowData(false, cell_list);
        ArrayList<String> columnName = new ArrayList<String>() {};
        columnName.add("HOTEN");
        columnName.add("MSSV");
        columnName.add("DiemTrungBinh");
        columnName.add("Lop");
        String query = "WHERE ((x.A = 1 and x.B = 'MN') OR x.C = 'JW') And (x.D = 4 OR x.H = '123')";
        String query1 = "WHERE (x.A = 1 AND x.B = 'MN') OR x.C = 'JW'";
        String query2 = "WHERE x.D = 4 oR x.H = '123'";
        String query3 = "WHERE sinhvien.id = '0912074'";
        String query4 = "WHERE (sinhvien.Lop='A' AND SINHVIEN.DiemTrungBinh>=8) AND SinhVien.HocBong='true' AND sinhvien.Ten = 'Dung'";
        String query5 = "WHERE sinhvien.id = '0912074';";
        String query6 = "WHERE sinhvien.Lop = 'A' AND SINHVIEN.DiemTrungBinh >= 8;";
        String query7= "WHERE (sinhvien.Lop='A' AND SINHVIEN.DiemTrungBinh>=8) or SinhVien.HocBong='true';";
        String nameTable = "SinhVien";
        String nameTable2 = "x";
        System.out.println(QueryParse(columnName, data, query));
        System.out.println(QueryParse(columnName, data, query1));
        System.out.println(QueryParse(columnName, data, query2));
        System.out.println(QueryParse(columnName, data, query3));
        System.out.println(QueryParse(columnName, data, query4));
        System.out.println(QueryParse(columnName, data, query5));
        System.out.println(QueryParse(columnName, data, query6));
        System.out.println(QueryParse(columnName, data, query7));
        
    }
}
